/**
 * 生命周期：
 *    概念：组件从创建到销毁的一系列过程
 *
 * 生命周期钩子函数：
 *    概念：在一个生命周期过程中，特定时机会触发的函数就叫做生命周期钩子函数。
 *    PS: 在 React 中，只有类组件有生命周期钩子函数，函数组件没有（16.8开始可以通过 hook 来模拟生命周期钩子）
 *
 * 生命周期钩子函数的图谱：
 *    https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
 *
 * 挂载阶段：
 *    1. constructor  构造函数
 *       应用场景：
 *          1. 初始化 state 的操作
 *          2. 提前绑定事件处理函数的this
 *       PS:
 *          1. 一般不需要声明，如果声明了的话，必须要调用 super()
 *    2. static getDerivedStateFromProps(props, state)
 *       应用场景：
 *          1. 实现类似与Vue中计算属性相关的内容
 *
 *       PS:
 *          1. 不能访问 this
 *          2. 不常用的。
 *          3. 横跨挂载阶段与更新阶段的。
 *          4. props - 当前的 props 数据
 *             state - 当前的 state 数据
 *          5. 必须要有返回值，可以是一个对象或一个null
 *             返回对象时，该对象会合并到组件的state上。
 *
 *    3. render()
 *       PS:
 *          1. 一个类组件必须要实现的一个函数
 *          2. 该函数的返回值作为组件的模板
 *          3. 纯函数不能包含有副作用
 *              副作用：
 *                1. 调用接口
 *                2. 直接操作真实DOM
 *                3. 直接修改外部数据，比如修改 state
 *
 *    4. componentDidMount()    挂载完成
 *       PS:
 *          1. 调用初始化接口
 *          2. 获取到真实DOM与修改真实DOM
 *          3. 订阅数据
 *          4. 监听全局事件，比如 滚动条之类的。
 *          5. 注意一些副作用需要在后续卸载时做收尾。
 *
 * 更新阶段：
 *     触发时机：New Props | setState()  |  force­Update()
 *    1. static getDerivedStateFromProps(props, state)
 *
 *    2. shouldComponentUpdate(nextProps, nextState)
 *        应用场景：
 *          1. 实现组件性能优化的一个钩子。（减少无用的 rerender）
 *
 *        PS:
 *          1. nextProps - 下一个Props
 *             nextState - 下一个State
 *          2. 必须要返回一个 boolean
 *              false - 阻止更新。阻止后续流程
 *              true  - 不阻止更新。继续下一个流程
 *          3. PureComponent 基础类 内部就是实现了该函数
 *          6. 当组件继承 PureComponent 时，不要再声明该钩子函数
 *          7. 通过 this.props 与 this.state 获取当前的数据，然后与 nextProps nextState 做比较从而决定返回值
 *    3. render()
 *
 *    4. getSnapshotBeforeUpdate(prevProps, prevState)
 *        应用场景：
 *          1. 获取到真实DOM更新之前的一些DOM相关的数据返回传递给更新完成
 *
 *        PS:
 *          1. 可以看成更新完成前的钩子，类似 beforeUpdate
 *          2. prevProps - 上一次的Props ,prevState - 上一次的State
 *          3. 必须要有返回值 or null, 该返回值会作为 componentDidUpdate 钩子的第三个参数
 *
 *    5. componentDidUpdate(prevProps, prevState, snapshot)
 *
 *        PS:
 *          1. prevProps - 上一次的Props, prevState - 上一次的State
 *          2. snapshot - getSnapshotBeforeUpdate 的返回值
 *          3. 能获取到数据更新且真实DOM更新之后的数据
 *          4. 不能再这儿不做条件判断的去修改数据
 *
 *  卸载阶段：
 *    1. component­Will­Unmount  组件将要卸载
 *        应用场景：
 *            1. 副作用清理工作： clearTimeout、clearInterval、removeEvenetListern、xxx.off()
 *
 */

import { Component } from "react";
import Hello from "./components/Hello";
import ScrollingList from "./components/ScrollingList";

interface IProps {}

interface IState {
  message: string;
  number: number;
  msgs: string[];
}

export default class App extends Component<IProps, IState> {
  state: Readonly<IState> = {
    message: "hello",
    number: 1,
    msgs: ["1", "2", "3"],
  };

  static getDerivedStateFromProps(props, state: IState) {
    // console.log("getDerivedStateFromProps", props, state);

    return {
      reverseMsg: state.message.split("").reverse().join(""),
    };
  }

  shouldComponentUpdate(nextProps, nextState: IState) {
    // console.log("shouldComponentUpdate", nextProps, nextState);
    // 1. 当 nextState.message 不为 world 就更新，否则就阻止
    // return nextState.message !== "world";

    // 2. 当 props 与 nextProps 有变化时才更新
    // return nextProps !== this.props; // 永远返回 false
    return true;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log("getSnapshotBeforeUpdate", prevProps, prevState);
    return "123";
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log("componentDidUpdate snapshot", snapshot);
  }

  render() {
    console.log("Render", this.props, this.state);

    const reverseMsg = this.state.message.split("").reverse().join("");

    return (
      <div>
        <ScrollingList list={this.state.msgs} />
        <hr />
        <button
          onClick={() =>
            this.setState((state) => ({
              msgs: [...state.msgs, state.msgs.length + 1 + ""],
            }))
          }
        >
          新增消息
        </button>

        <h1>App</h1>
        <p>message: {this.state.message}</p>
        <p>reverseMsg: {reverseMsg}</p>
        <p>number: {this.state.number}</p>
        <button onClick={() => this.setState({ message: "world" })}>
          按钮1
        </button>
        <button onClick={() => this.setState({ message: "world2" })}>
          按钮2
        </button>
        <button
          onClick={() =>
            this.setState((state) => ({
              number: state.number + 1,
            }))
          }
        >
          按钮3
        </button>
        <button
          onClick={() =>
            this.setState(() => ({
              number: 1,
            }))
          }
        >
          按钮4
        </button>

        <hr />

        <Hello count={this.state.number} msg={this.state.message} />
      </div>
    );
  }
}
